package com.ly.common.util;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.regex.PatternSyntaxException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
	/**
	 * 压缩文件列表到某ZIP文件
	 * @param zipFilename 要压缩到的ZIP文件
	 * @param path 文件列表，多参数
	 * @throws Exception
	 */
	public static void zip(String zipFilename, String path, String... excludeFileMasks) throws IOException {
		zip(new FileOutputStream(zipFilename), path, excludeFileMasks);
	}

	/**
	 * 压缩文件列表到输出流
	 * @param os 要压缩到的流
	 * @param path 文件列表，多参数
	 * @throws Exception
	 */
	public static void zip(OutputStream os, String path, String... excludeFileMasks) throws IOException {
		ZipOutputStream zos = new ZipOutputStream(os);
		try {
			if (path == null || path.trim().isEmpty()) {
				return;
			}
			File file = new File(path);
			if (file.exists()) {
				if (file.isDirectory()) {
					zipDirectory(zos, file.getPath(), file.getName() + File.separator, excludeFileMasks);
				} else {
					zipFile(zos, file.getPath(), "");
				}
			}
		} finally {
			//zos.finish();
			try{
				zos.close();
			}catch (IOException e){
				System.out.println(e.getMessage());
				// continue;
			}
		}
	}

	public static ArrayList<String> unzip(String sZipPathFile, String sDestPath) throws IOException {
		ArrayList<String> allFileName = new ArrayList<String>();
		FileInputStream fins = null;
		ZipInputStream zins = null;
		try {
			// 先指定压缩档的位置和档名，建立FileInputStream对象
			fins = new FileInputStream(sZipPathFile);
			// 将fins传入ZipInputStream中
			String charset = "GBK";
			zins = new ZipInputStream(fins, Charset.forName(charset));
			ZipEntry ze = null;
			byte[] ch = new byte[256];
			while ((ze = zins.getNextEntry()) != null) {
				File zfile = new File(sDestPath + ze.getName());
				File fpath = new File(zfile.getParentFile().getPath());
				if (ze.isDirectory()) {
					if (!zfile.exists())
						zfile.mkdirs();
					zins.closeEntry();
				} else {
					if (!fpath.exists())
						fpath.mkdirs();
					FileOutputStream fouts = new FileOutputStream(zfile);
					try {
						int i;
						allFileName.add(zfile.getAbsolutePath());
						while ((i = zins.read(ch)) != -1)
							fouts.write(ch, 0, i);
						zins.closeEntry();
					} finally {
						fouts.close();
					}
				}
			}
		} finally {
			IOUtils.close(zins, fins);
		}
		return allFileName;
	}

	private static void zipDirectory(ZipOutputStream zos, String dirName, String basePath, String... excludeFileMasks)
			throws IOException {
		File dir = new File(dirName);
		if (dir.exists()) {
			File files[] = null;
			if (excludeFileMasks.length > 0) {
				files = dir.listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						for (String excludeFileMask : excludeFileMasks) {
							String regex = castFileFilterRegex(excludeFileMask);
							if (regex == null || name.matches(regex)) {
								return false;
							}
						}
						return true;
					}
				});
			} else {
				files = dir.listFiles();
			}
			if (files.length > 0) {
				for (File file : files) {
					if (file.isDirectory()) {
						zipDirectory(zos, file.getPath(),
								basePath + file.getName().substring(file.getName().lastIndexOf(File.separator) + 1)
										+ File.separator);
					} else
						zipFile(zos, file.getPath(), basePath);
				}
			} else {
				ZipEntry ze = new ZipEntry(basePath);
				zos.putNextEntry(ze);
			}
		}
	}

	private static void zipFile(ZipOutputStream zos, String filename, String basePath) throws IOException {
		File file = new File(filename);
		if (file.exists()) {
			FileInputStream fis = new FileInputStream(filename);
			try {
				ZipEntry ze = new ZipEntry(basePath + file.getName());
				zos.putNextEntry(ze);
				byte[] buffer = new byte[8192];
				int count = 0;
				while ((count = fis.read(buffer)) > 0) {
					zos.write(buffer, 0, count);
				}
			} finally {
				fis.close();
			}
		}
	}

	private static String castFileFilterRegex(String fileMask) {
		try {
			return fileMask.replaceAll("\\.", "\\\\.")
					.replaceAll("\\(", "\\\\(")
					.replaceAll("\\)", "\\\\)")
					.replaceAll("\\*", "\\.*?");
		} catch (PatternSyntaxException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static void main(String[] args) throws IOException {
//		String re = castFileFilterRegex("*(*).*");
//		System.out.println("测试(vue)html".matches(re));
		zip("d:/a.zip","d:/api");
	}
}
